import CryptoJS from "crypto-js";
import axios from "axios";
import { jwtDecode } from "jwt-decode";
import sm4 from "./sm4";
import { RUM_CONTEXT, SERVICE_ID, SM4_KEY, SCAN_EVENT } from "./constants";

const mockNativeClient = axios.create({
  baseURL: "/native/api",
});

export const createAction = (type, payload) => {
  return payload ? { type, payload } : { type };
};

export const getRequest = (serviceId, payload, sign) => ({
  requestHeader: {
    serviceContext: {
      serviceId,
      channel: "PDA",
    },
    rumContext: RUM_CONTEXT,
    timestamp: new Date().getTime(),
  },
  payload: payload ? payload : null,
  sign,
});

export const getMatryoshkaRequest = (payload, sign) => {
  return getRequest(SERVICE_ID.MATRYOSHKA, payload, sign);
};

export const getDachshundRequest = (payload, sign) => {
  return getRequest(SERVICE_ID.DACHSHUND, payload, sign);
};

export const generateSignStr = (nonce, params) => {
  let raw = [];

  if (params && params.length > 0) {
    for (let param of params) {
      if (param) {
        raw.push(param);
      }
    }
  }

  let rawSignTxt = raw.join("|");
  if (nonce) {
    rawSignTxt = rawSignTxt.length > 0 ? nonce + "|" + rawSignTxt : nonce;
  }

  // eslint-disable-next-line
  return CryptoJS.MD5(rawSignTxt).toString();
};

export const getTenantId = (token) => {
  let payload = jwtDecode(token);
  return sm4.decode({
    input: payload.tenantId,
    key: SM4_KEY,
  }).substring(0, 36);
};

export const getRealName = (token) => {
  let payload = jwtDecode(token);
  return payload.realName;
};

export const getNativeApiRequest = ({
  classFullName,
  action,
  params,
  needNonce,
}) => {
  let nonce = null;
  if (needNonce) {
    let nonceArray = window.sessionStorage.getItem("nonceArray")?.split(",");
    nonce = nonceArray ? nonceArray.shift() : null;
    if (nonce) {
      window.sessionStorage.setItem("nonceArray", nonceArray);
    }
  }

  return {
    action,
    payload: {
      classFullName,
      nonce,
      token: window.sessionStorage.getItem("token"),
      ip: needNonce ? window.localStorage.getItem("SERVER_IP") : null,
      params,
    },
  };
};

export const callNativeApi = ({ classFullName, action, params, needNonce }) => {
  let request = getNativeApiRequest({
    classFullName,
    action,
    params,
    needNonce,
  });
  if ("cordova" in window) {
    // on device
    return new Promise((resolve, reject) => {
      window.cordova.plugins.NativeInvoker.callNativeMethod(
        request,
        (successData) => {
          let succObj = JSON.parse(successData);
          if (needNonce) {
            let nonceArray = window.sessionStorage.getItem("nonceArray");
            if (!nonceArray) {
              nonceArray = [];
            } else {
              nonceArray = nonceArray.split(",");
            }
            nonceArray.push(succObj.result.nonce);
            window.sessionStorage.setItem("nonceArray", nonceArray);
          }
          resolve(succObj);
        },
        (error) => reject(error)
      );
    });
  } else {
    // mock env
    let pkgArray = classFullName.split(".");
    return mockNativeClient.post(
      `/${pkgArray[pkgArray.length - 1]}/${action}`,
      request
    );
  }
};

export const subscribeScanEvent = (cb) => {
  window.broadcaster?.addEventListener(SCAN_EVENT, true, cb);
};

export const unSubscribeScanEvent = (cb) => {
  window.broadcaster?.removeEventListener(SCAN_EVENT, cb);
};

export const filterEmptyProperties = (obj) => {
  const filteredObj = {};

  for (const key in obj) {
    const value = obj[key];

    if (typeof value === "object" && value !== null) {
      const nestedObj = filterEmptyProperties(value);

      if (Object.keys(nestedObj).length > 0) {
        filteredObj[key] = nestedObj;
      }
    } else if (
      value !== null &&
      value !== undefined &&
      value !== "" &&
      !/^(null|undefined)$/.test(value)
    ) {
      filteredObj[key] = value;
    }
  }

  return filteredObj;
};
